package archivemanagement;

import static com.google.common.base.Throwables.propagate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;

import metagrammar.Operator;
import parsetree.OperatorSpec;
import util.SpecWithSameOperatorCollection;
import util.SpecWithSameOperatorCollection.ConstructionException;

import com.google.common.collect.LinkedListMultimap;
import com.google.inject.Inject;

public class SpecManager implements ArchiveManager<Operator, Collection<OperatorSpec>> {
    
    private final ArrayList<SpecArchive> libraries;
    
    @Inject
    private SpecManager(SpecArchive... specLibraries)
    {
        libraries = new ArrayList<SpecArchive>(Arrays.asList(specLibraries));
    }
    
    @Override
    public Collection<OperatorSpec> load(Operator key)
    {
        for(SpecArchive lib : libraries) {
            Collection<OperatorSpec> spec;
            try {
                spec = lib.loadSpecs(key);
                if(spec != null) {
                    return spec;
                }
            }
            catch(IOException e) {
                propagate(e);
            }
        }
        return null;
    }
    
    @Override
    public void add(Collection<OperatorSpec> value)
    {
        LinkedListMultimap<Operator, OperatorSpec> map = LinkedListMultimap.create();
        for(OperatorSpec spec : value) {
            map.put(spec.getOperator(), spec);
        }
        Collection<Collection<OperatorSpec>> vals = map.asMap().values();
        LinkedList<SpecWithSameOperatorCollection> a = new LinkedList<SpecWithSameOperatorCollection>();
        for(Collection<OperatorSpec> col : vals) {
            try {
                SpecWithSameOperatorCollection c = new SpecWithSameOperatorCollection(col
                        .iterator().next().getOperator(), ArrayList.class);
                c.addAll(col);
                a.add(c);
            }
            catch(ConstructionException e) {
                throw propagate(e);
            }
        }
        for(SpecArchive lib : libraries) {
            try {
                lib.writeSpecs(a.toArray(new SpecWithSameOperatorCollection[0]));
            }
            catch(IOException e) {
                propagate(e);
            }
        }
    }
    
    @Override
    public Collection<Collection<OperatorSpec>> loadAll()
    {
        ArrayList<Collection<OperatorSpec>> specs = new ArrayList<Collection<OperatorSpec>>();
        for(SpecArchive lib : libraries) {
            try {
                specs.addAll(lib.loadAllSpecs());
            }
            catch(IOException e) {
                propagate(e);
            }
        }
        return specs;
    }
    
    @Override
    public int update(Collection<OperatorSpec> value)
    {
        //TODO
        return 0;
    }
    
}